2장. 마이크로서비스의 그림자
1장에서 우리는 마이크로서비스의 장점을 살펴보았다.
독립 배포, 독립 확장, 장애 격리.
하지만 구조를 나눈다는 것은
단순히 깔끔해지는 일이 아니다.
보이지 않던 문제들이
겉으로 드러나는 일이기도 하다.
이 장에서는
마이크로서비스가 만들어내는 현실적인 변화들을 살펴본다.
함수 호출이 아니라, 네트워크 호출이다
모놀리스에서는 이런 일이 자연스럽다.
주문 생성 → 결제 함수 호출 → 포인트 적립 함수 호출
같은 프로그램 안에서 호출된다.
실패 가능성은 거의 없다.
하지만 마이크로서비스에서는 다르다.
주문 서비스 → (네트워크) → 결제 서비스 → (네트워크) → 포인트 서비스
이제 호출은 네트워크를 건너간다.
그리고 네트워크는 완벽하지 않다.
- 잠시 느려질 수 있다
- 응답이 늦어질 수 있다
- 중간에 끊길 수 있다
- 상대 서비스가 일시적으로 죽어 있을 수 있다
이제 단순한 함수 호출이 아니라
실패를 전제로 설계해야 하는 호출이 된다.
모든 것이 한 번에 끝나지 않는다
모놀리스에서는 이런 보장이 있다.
- 주문 생성
- 결제 성공
- 포인트 적립
이 세 가지가 하나라도 실패하면 모두 취소된다.
사용자는 항상 “완성된 상태”만 보게 된다.
하지만 마이크로서비스에서는
상황이 달라질 수 있다.
예를 들어,
- 주문은 정상 생성되었다
- 결제는 성공했다
- 하지만 포인트 적립 서비스가 잠시 멈춰 있었다
이 경우 사용자는
- 주문 내역은 보이는데
- 포인트는 아직 적립되지 않은 상태를 보게 될 수 있다
조금 뒤에 포인트는 정상적으로 들어온다.
이처럼
일부 정보가 잠시 늦게 반영되는 상태를 허용하는 방식을
최종 일관성(Eventual Consistency)이라고 부른다.
중요한 것은,
데이터가 틀리는 것이 아니라
“시간 차이를 허용한다”는 점이다.
디버깅이 달라진다
모놀리스에서는 로그를 한 곳에서 보면 된다.
하지만 마이크로서비스에서는
- 주문 서비스 로그
- 결제 서비스 로그
- 포인트 서비스 로그
- 메시지 큐 로그
를 모두 확인해야 한다.
하나의 사용자 요청이
여러 서비스를 거쳐 이동하기 때문이다.
문제가 생기면
“어디에서 멈췄는지”를 추적해야 한다.
이제 디버깅은 코드 추적이 아니라
흐름 추적이 된다.
배포는 쉬워지지만, 관리 대상은 늘어난다
모놀리스는 하나만 배포하면 된다.
마이크로서비스는 서비스 수만큼
배포 대상이 존재한다.
- 버전 충돌 문제
- API 변경 문제
- 호환성 문제
- 롤백 전략
자동화가 없다면
운영 난이도는 오히려 높아질 수 있다.
데이터는 더 이상 중앙에서 보호되지 않는다
모놀리스에서는 하나의 데이터베이스가
모든 데이터를 관리한다.
마이크로서비스에서는
각 서비스가 자신의 데이터를 가진다.
이 말은 곧,
- 다른 서비스 데이터는 직접 수정할 수 없고
- 반드시 API나 이벤트를 통해 요청해야 하며
- 데이터 정합성은 협업으로 맞춰야 한다는 뜻이다
설계가 부족하면
데이터가 서로 어긋나는 일이 생길 수 있다.
장애는 사라지지 않는다
마이크로서비스는 장애를 없애는 구조가 아니다.
다만,
하나가 죽어도
전체가 같이 죽지 않게 만드는 구조
다.
그러려면
- 응답 대기 시간 설정
- 재시도 정책
- 과도한 호출 차단
- 트래픽 제한
같은 설계가 필요하다.
이 준비가 없다면
구조를 나누어도 장애는 그대로 전파된다.
우리가 스스로에게 던져야 할 질문
마이크로서비스의 장점이 매력적으로 보이더라도
다음 질문에 답해보아야 한다.
- 우리는 네트워크 실패를 설계로 다뤄본 경험이 있는가?
- 일부 데이터가 잠시 늦게 반영되는 상황을 받아들일 수 있는가?
- 로그와 모니터링 체계가 준비되어 있는가?
- 자동 배포 환경이 구축되어 있는가?
준비되지 않은 상태에서 전환하면
복잡성만 증가할 수 있다.
이 장의 결론
마이크로서비스는 더 강력한 구조다.
하지만 더 많은 책임을 요구한다.
모놀리스의 문제를 해결하는 대신
새로운 문제를 가져온다.
중요한 것은
장점만 보고 선택하지 않는 것이다.
우리는 이제 장점과 그림자를 모두 보았다.